﻿using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

/// <summary>
/// 高性能异步日志记录器（支持自定义文件名称）
/// </summary>
public sealed class AsyncLogger : IDisposable
{
    // 配置参数
    private const int MaxFileSize = 1024 * 1024 * 10; // 1MB
    private const int MaxRetainedFiles = 30; // 最多保留30个文件
    private const string LogFileExtension = ".txt";
    private static readonly Encoding LogEncoding = Encoding.UTF8;
    
    // 日志写入器缓存（按文件名称分组）
    private static readonly ConcurrentDictionary<string, LoggerInstance> _loggers = 
        new ConcurrentDictionary<string, LoggerInstance>(StringComparer.OrdinalIgnoreCase);
    
    // 日志根目录（从配置读取）
    private static string LogRootDirectory { get; } = GetLogRootDirectory();
    
    // 清理定时器
    private static readonly Timer _cleanupTimer = new Timer(CleanupUnusedLoggers, null, 
        TimeSpan.FromHours(1), TimeSpan.FromHours(1));

    /// <summary>
    /// 写入日志（指定文件名称）
    /// </summary>
    public static Task WriteLogAsync(string fileName, string message)
    {
        var logger = _loggers.GetOrAdd(fileName, name => new LoggerInstance(name));
        return logger.WriteAsync(message);
    }

    /// <summary>
    /// 获取日志根目录
    /// </summary>
    private static string GetLogRootDirectory()
    {
        // 伪代码：从配置获取基础路径
        string basePath = null; // 替换为实际配置获取逻辑
        
        return string.IsNullOrEmpty(basePath) 
            ? Path.Combine(Environment.CurrentDirectory, "Logs") 
            : Path.Combine(basePath, "Logs");
    }

    /// <summary>
    /// 清理不使用的日志记录器
    /// </summary>
    private static void CleanupUnusedLoggers(object state)
    {
        foreach (var entry in _loggers)
        {
            if (entry.Value.CanDispose())
            {
                if (_loggers.TryRemove(entry.Key, out var logger))
                {
                    logger.Dispose();
                }
            }
        }
    }

    public static void Shutdown()
    {
        _cleanupTimer.Dispose();
        foreach (var logger in _loggers.Values)
        {
            logger.Dispose();
        }
        _loggers.Clear();
    }

    public void Dispose()
    {
        _cleanupTimer.Dispose();
    }

    /// <summary>
    /// 实际的日志写入器实例
    /// </summary>
    private class LoggerInstance : IDisposable
    {
        private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
        private readonly string _logName;
        private StreamWriter _writer;
        private DateTime _currentDate;
        private string _currentFilePath;
        private int _currentFileIndex = 1;
        private DateTime _lastWriteTime = DateTime.UtcNow;
        private bool _disposed;

        public LoggerInstance(string logName)
        {
            _logName = logName;
            InitializeLogDirectory();
            InitializeFileWriter();
        }

        public async Task WriteAsync(string message)
        {
            _lastWriteTime = DateTime.UtcNow;
            await _semaphore.WaitAsync().ConfigureAwait(false);
            try
            {
                // 检查是否需要滚动文件
                await RotateFileIfNeededAsync().ConfigureAwait(false);
                
                // 添加时间戳并写入
                var logEntry = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} {message}";
                await _writer.WriteLineAsync(logEntry).ConfigureAwait(false);
                await _writer.FlushAsync().ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                // 最低限度的错误处理
                Console.Error.WriteLine($"[{_logName}] Log write failed: {ex.Message}");
            }
            finally
            {
                _semaphore.Release();
            }
        }

        public bool CanDispose() => (DateTime.UtcNow - _lastWriteTime) > TimeSpan.FromMinutes(30);

        private async Task RotateFileIfNeededAsync()
        {
            // 检查日期变更
            if (DateTime.Now.Date != _currentDate)
            {
                await CloseWriterAsync().ConfigureAwait(false);
                InitializeLogDirectory();
                _currentFileIndex = 1;
                InitializeFileWriter();
                return;
            }

            // 检查文件大小
            if (_writer?.BaseStream != null && _writer.BaseStream.Length > MaxFileSize)
            {
                await CloseWriterAsync().ConfigureAwait(false);
                _currentFileIndex++;
                InitializeFileWriter();
            }
        }

        private void InitializeLogDirectory()
        {
            _currentDate = DateTime.Now.Date;
            var dateDir = Path.Combine(LogRootDirectory, _currentDate.ToString("yyyy-MM-dd"));
            
            if (!Directory.Exists(dateDir))
            {
                Directory.CreateDirectory(dateDir);
            }
        }

        private void InitializeFileWriter()
        {
            // 生成文件名 (e.g., AppLog_2023-10-01_001.txt)
            var fileName = $"{_logName}_{_currentDate:yyyy-MM-dd}_{_currentFileIndex:D3}{LogFileExtension}";
            _currentFilePath = Path.Combine(
                LogRootDirectory, 
                _currentDate.ToString("yyyy-MM-dd"), 
                fileName);
            
            // 创建或追加到文件
            _writer = new StreamWriter(
                new FileStream(
                    _currentFilePath, 
                    FileMode.Append, 
                    FileAccess.Write, 
                    FileShare.Read, 
                    bufferSize: 4096, 
                    useAsync: true), 
                LogEncoding);
        }

        private async Task CloseWriterAsync()
        {
            if (_writer != null)
            {
                await _writer.FlushAsync().ConfigureAwait(false);
                _writer.Dispose();
                _writer = null;
            }
        }

        public void Dispose()
        {
            if (_disposed) return;
            
            _semaphore.Wait();
            try
            {
                CloseWriterAsync().GetAwaiter().GetResult();
                _disposed = true;
            }
            finally
            {
                _semaphore.Release();
            }
        }
    }
}